package com.sdy.resdir.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sdy.approval.api.ApprovalAllApi;
import com.sdy.approval.biz.model.TpApproveFlowConfig;
import com.sdy.approval.biz.model.TpOrder;
import com.sdy.common.model.BizException;
import com.sdy.common.utils.Assert;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.sdy.resdir.biz.mapper.RdResourceApplicationDetailMapper;
import com.sdy.resdir.biz.model.RdDbApp;
import com.sdy.resdir.biz.model.RdOrderApp;
import com.sdy.resdir.biz.model.RdResourceApplicationDetail;
import com.sdy.resdir.biz.model.RdResourceDir;
import com.sdy.resdir.biz.service.RdDbAppService;
import com.sdy.resdir.biz.service.RdOrderAppService;
import com.sdy.resdir.biz.service.RdResourceApplicationDetailService;
import com.sdy.resdir.biz.service.RdResourceDirService;
import com.sdy.usercenter.api.UserQueryApi;
import com.sdy.usercenter.api.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 申请资源详细（子） 服务实现类
 * </p>
 *
 * @author hyh
 * @since 2019-10-21
 */
@Slf4j
@Service
public class RdResourceApplicationDetailServiceImpl extends BaseServiceImpl<RdResourceApplicationDetail> implements RdResourceApplicationDetailService {
    @Autowired
    private RdResourceApplicationDetailMapper rdResourceApplicationDetailMapper;
    @Autowired
    private ApprovalAllApi approvalAllApi;
    @Autowired
    private RdResourceDirService rdResourceDirService;
    @Autowired
    private RdResourceApplicationDetailService resAppDetailService;
    @Autowired
    private UserQueryApi userQueryApi;
    @Autowired
    private RdOrderAppService rdOrderAppService;
    @Autowired
    private RdDbAppService rdDbAppService;
    @Value("${res.app.code}")
    private String appCode;
    @Value("${res.dept.code}")
    private String deptCode;
    @Value("${res.approval.authCode}")
    private String authCode;
    @Value("${res.approval.roleCode}")
    private String roleCode;

    @Override
    public Boolean updateApplyDetail(RdResourceApplicationDetail rdResourceApplicationDetail, Integer userId, Date date) throws BizException {

        RdResourceApplicationDetail oneDetail = resAppDetailService.getOne(Wrappers.<RdResourceApplicationDetail>lambdaQuery()
                .eq(RdResourceApplicationDetail::getId, rdResourceApplicationDetail.getId()));
        rdResourceApplicationDetail.setModifyTime(date).setModifyUserId(userId);
        String applicationNum = oneDetail.getApplyNumChild();
        //判断是否被人修改过
        Integer state = resAppDetailService.getOne(Wrappers.<RdResourceApplicationDetail>lambdaQuery()
                .eq(RdResourceApplicationDetail::getApplyNumChild, applicationNum)
                .isNull(RdResourceApplicationDetail::getVersionNum)).getState();
        Assert.isTrue(state != 7, "该订单已被他人修改,请您刷新数据!");
        Integer resId = oneDetail.getResId();
        Integer isRelease = rdResourceDirService.getOne(Wrappers.<RdResourceDir>lambdaQuery().eq(RdResourceDir::getId, resId)).getIsRelease();
        Assert.isTrue(isRelease == 0, "该资源已下架,暂不支持提交!");
        // 查询当前订单
        List<TpOrder> orders = approvalAllApi.selectOrderByApplyNum(applicationNum, 1);
        // 拿到该订单的状态
        Integer gsOrderState = orders.get(0).getGsOrderState();
        if (gsOrderState == 3) {
            Assert.isTrue(true, "该订单正在审批中,请勿修改!");
        } else if (gsOrderState == 4) {
            Assert.isTrue(true, "该订单正在审批中,请勿修改!");
        } else if (gsOrderState == 7) {
            RdResourceDir oneDir = rdResourceDirService.getOne(Wrappers.<RdResourceDir>lambdaQuery()
                    .eq(RdResourceDir::getId, oneDetail.getResId()));
            if (oneDir.getResType() == 1) {
                // 找到具有版本的自建系统
                List<RdOrderApp> orderApps = rdOrderAppService.list(Wrappers.<RdOrderApp>lambdaQuery()
                        .eq(RdOrderApp::getApplyNum, applicationNum).isNotNull(RdOrderApp::getVersionNum));
                // 如果之前没有产生过历史版本
                int versionMax;
                if (orderApps.isEmpty()) {
                    versionMax = 1;
                } else {
                    // 如果之前就已经有版本
                    List<Integer> versions = orderApps.stream().map(RdOrderApp::getVersionNum).collect(Collectors.toList());
                    versionMax = Collections.max(versions)+1;
                }
                // 自建系统新增本版
                boolean update = rdOrderAppService.update(Wrappers.<RdOrderApp>lambdaUpdate()
                        .eq(RdOrderApp::getApplyNum, applicationNum).isNull(RdOrderApp::getVersionNum)
                        .set(RdOrderApp::getVersionNum, versionMax).set(RdOrderApp::getModifyTime, date));
                Assert.notTrue(update, "自建系统新增版本数据时出错!");

                // 存储新的自建系统数据
                List<RdOrderApp> orderAppsNew = rdResourceApplicationDetail.getOrderApps();
                Assert.isTrue(orderAppsNew.isEmpty(), "您未选择自建系统");
                // 批量新增自建系统
                boolean b = rdOrderAppService.addOrderApps(applicationNum, orderAppsNew, userId, date);
                Assert.isTrue(!b, "新增自建系统时失败");
            } else if (oneDir.getResType() == 3) {
                List<RdDbApp> dbApps = rdResourceApplicationDetail.getDbApps();
                List<RdDbApp> dbAppList = rdDbAppService.list(Wrappers.<RdDbApp>lambdaQuery().eq(RdDbApp::getApplyNum, applicationNum)
                        .isNotNull(RdDbApp::getVersionNum));
                List<Integer> verSion = dbAppList.stream().map(RdDbApp::getVersionNum).collect(Collectors.toList());
                // 先生成历史版本数据
                boolean update;
                Integer verMax;
                if (verSion.isEmpty()) {
                    verMax = 1;
                } else {
                    verMax = Collections.max(verSion) + 1;
                }
                update = rdDbAppService.update(Wrappers.<RdDbApp>lambdaUpdate().eq(RdDbApp::getApplyNum, applicationNum)
                        .isNull(RdDbApp::getVersionNum).set(RdDbApp::getVersionNum, verMax));
                Assert.notTrue(update, "修改时出现错误!(生成历史数据时出错!)");
                // 再新增修改后的数据
                Boolean aBoolean = rdDbAppService.addBetch(applicationNum, dbApps);
                Assert.notTrue(aBoolean, "新增资源信息出现错误!");
            }
            boolean updateDetail = resAppDetailService.updateById(rdResourceApplicationDetail.setState(3));
            Assert.notTrue(updateDetail, "修改本地订单出错");
            // 清除冗余数据出错
            Boolean aBoolean = approvalAllApi.updateFlow(applicationNum, userId);
            Assert.notTrue(aBoolean, "调用approval远程接口时报错");
        }
        return true;
    }

    /**
     * 新增流程配置模板
     *
     * @param map
     * @param date
     * @param userId
     * @return
     * @throws Exception
     */
    @Override
    public Boolean addApprovalConfigDetail(Map<String, Object> map, Date date, Integer userId ,Integer operateType) throws Exception {
        Integer resId = (Integer) map.get("resId");
        Integer resPower = (Integer) map.get("resPower");
        String prefix = "[资源目录]-已归集";
        String strResId = prefix + resId;
        List<TpApproveFlowConfig> configs = approvalAllApi.selectApprovalByResId(strResId);
        List<Integer> deptIdList = new ArrayList<>();
        List<Integer> roleIdList = new ArrayList<>();
        if (operateType == 0) {
            LambdaUpdateWrapper<RdResourceDir> rdResourceDirWrapper = new LambdaUpdateWrapper<>();
            rdResourceDirWrapper.eq(RdResourceDir::getId, resId).set(RdResourceDir::getIsRelease, 1);
            boolean update = rdResourceDirService.update(rdResourceDirWrapper);
            Assert.notTrue(update, "更新资源为上线状态时出错!");
        }
        // 公开
        if (resPower == 1) {
            int deptId = userQueryApi.getDeptByCode(deptCode).getId();
            int roleId = userQueryApi.getRoleByCode(roleCode).getId();
            deptIdList.add(deptId);
            roleIdList.add(roleId);
            // 判断是否改变流程配置模板
            // 没有改变流程配置模板
            if (configs.size() == 1) {
                RdResourceDir oneDir = rdResourceDirService.getOne(Wrappers.<RdResourceDir>lambdaQuery().eq(RdResourceDir::getId, resId));
                oneDir.setId(resId).setResPower(resPower).setModifyTime(date);
                rdResourceDirService.updateById(oneDir);
                return true;
            } else if (configs.size() == 0) {
                // 调用流程配置接口
                String insertApproval = approvalAllApi.insertApproval(deptIdList, roleIdList, prefix, resId.toString());
                Assert.isTrue("移除配置失败".equals(insertApproval), "移除配置失败");
                Assert.isTrue(insertApproval.equals("缺失部门的对应角色"), "缺失部门的对应角色");
                Assert.isTrue(insertApproval.equals("缺失角色的对应部门"), "缺失角色的对应部门");
                Assert.notTrue(insertApproval.equals("流程生成成功"), "流程生成失败");
                // 同步dir里面的来源部门数据
                LambdaUpdateWrapper<RdResourceDir> upDir = new LambdaUpdateWrapper<>();
                upDir.eq(resId != null && !resId.equals(""), RdResourceDir::getId, resId)
                        .set(RdResourceDir::getResPowerDeptId, deptId)
                        .set(RdResourceDir::getResPowerDept, userQueryApi.getDeptByCode(deptCode).getName())
                        .set(RdResourceDir::getReleaseTime, new Date())
                        .set(resPower != null, RdResourceDir::getResPower, resPower)
                        .set(RdResourceDir::getModifyTime, date);
                Assert.notTrue(rdResourceDirService.update(upDir), "同步到dir时出错");
                return true;
            } else if (configs.size() == 2) {
                Integer lowerShelfRes = approvalAllApi.lowerShelfRes(deptIdList, roleIdList, prefix, resId, userId, date);
                Assert.notTrue(lowerShelfRes == 1, "重新发布失败！");
                // 同步dir里面的来源部门数据
                LambdaUpdateWrapper<RdResourceDir> upDir = new LambdaUpdateWrapper<>();
                upDir.eq(resId != null && !resId.equals(""), RdResourceDir::getId, resId)
                        .set(RdResourceDir::getResPowerDeptId, map.get("deptId"))
                        .set(RdResourceDir::getResPowerDept, userQueryApi.getDeptByCode(deptCode).getName())
                        .set(RdResourceDir::getReleaseTime, new Date())
                        .set(resPower != null, RdResourceDir::getResPower, resPower)
                        .set(RdResourceDir::getModifyTime, date);
                Assert.notTrue(rdResourceDirService.update(upDir), "同步到dir时出错");
                return true;
            }
        } else if (resPower == 2) {
            Integer idForApproval = userQueryApi.getDeptByCode(deptCode).getId();
            Integer deptId = (Integer) map.get("deptId");
            int roleId = userQueryApi.getRoleByCode(roleCode).getId();
            deptIdList.add(deptId);
            roleIdList.add(roleId);
            deptIdList.add(idForApproval);
            roleIdList.add(roleId);
            // 若同一流程被同一部门的审批角色审批两次，则无意义
            Assert.isTrue(idForApproval.equals(deptId), "该流程被同一部门审批角色审批两次或以上!");
            if (configs.size() == 2 && configs.get(0).getAuditDepartmentId().equals(deptId)) {
                RdResourceDir oneDir = rdResourceDirService.getOne(Wrappers.<RdResourceDir>lambdaQuery().eq(RdResourceDir::getId, resId));
                oneDir.setId(resId).setResPower(resPower).setModifyTime(date);
                rdResourceDirService.updateById(oneDir);
                return true;
            } else if (configs.size() == 0) {
                // 调用流程配置接口
                String insertApproval = approvalAllApi.insertApproval(deptIdList, roleIdList, prefix, resId.toString());
                Assert.isTrue(insertApproval.equals("移除配置失败"), "移除配置失败");
                Assert.isTrue(insertApproval.equals("缺失部门的对应角色"), "缺失部门的对应角色");
                Assert.isTrue(insertApproval.equals("缺失角色的对应部门"), "缺失角色的对应部门");
                Assert.notTrue(insertApproval.equals("流程生成成功"), "流程生成失败");
                // 同步dir里面的来源部门数据
                LambdaUpdateWrapper<RdResourceDir> upDir = new LambdaUpdateWrapper<>();
                upDir.eq(resId != null && !resId.equals(""), RdResourceDir::getId, resId)
                        .set(RdResourceDir::getResPowerDeptId, map.get("deptId"))
                        .set(RdResourceDir::getResPowerDept, userQueryApi.getDept((Integer) map.get("deptId")).getName())
                        .set(RdResourceDir::getReleaseTime, new Date())
                        .set(resPower != null, RdResourceDir::getResPower, resPower)
                        .set(RdResourceDir::getModifyTime, date);
                Assert.notTrue(rdResourceDirService.update(upDir), "同步到dir是出错");
                return true;
            } else if ((configs.size() == 2 && !configs.get(0).getAuditDepartmentId().equals(deptId)) || configs.size() == 1) {
                Integer lowerShelfRes = approvalAllApi.lowerShelfRes(deptIdList, roleIdList, prefix, resId, userId, date);
                Assert.notTrue(lowerShelfRes == 1, "重新发布失败！");
                // 同步dir里面的来源部门数据
                LambdaUpdateWrapper<RdResourceDir> upDir = new LambdaUpdateWrapper<>();
                upDir.eq(resId != null && !resId.equals(""), RdResourceDir::getId, resId)
                        .set(RdResourceDir::getResPowerDeptId, map.get("deptId"))
                        .set(RdResourceDir::getResPowerDept, userQueryApi.getDept((Integer) map.get("deptId")).getName())
                        .set(RdResourceDir::getReleaseTime, new Date())
                        .set(resPower != null, RdResourceDir::getResPower, resPower)
                        .set(RdResourceDir::getModifyTime, date);
                Assert.notTrue(rdResourceDirService.update(upDir), "同步到dir是出错");
                return true;
            }
        }
        return true;
    }

    /**
     * 已上线资源申请单提交(单条独立申请)
     *
     * @param rdResourceApplicationDetail
     * @return
     */
    @Override
    public Boolean saveApply(RdResourceApplicationDetail rdResourceApplicationDetail, Integer userId, String randomNum) throws BizException {
        // 准备需要的数据
        // 获取随机申请订单
        Date date = new Date();
        Integer intResId = rdResourceApplicationDetail.getIdList().get(0);
        RdResourceDir rdResourceDir = rdResourceDirService.getOne(new LambdaQueryWrapper<RdResourceDir>().eq(RdResourceDir::getId, intResId));
        Assert.isTrue(rdResourceDir != null && rdResourceDir.getIsRelease() == 0, "资源已下架");
        // 获取资源的主键id
        String applyNum = randomNum + "-" + intResId;
        // 防止同一用户再次提交同一资源的申请
        UserDTO user = userQueryApi.getUser(userId);
        List<RdResourceApplicationDetail> listDetail = resAppDetailService.list(Wrappers.<RdResourceApplicationDetail>lambdaQuery()
                .eq(intResId != null, RdResourceApplicationDetail::getResId, userId)
                .eq(RdResourceApplicationDetail::getApplyUserId, userId)
                .in(RdResourceApplicationDetail::getState, 2, 3, 4, 6));
        Assert.notTrue(listDetail.isEmpty(), "该资源您已申请!");
        // 获取资源信息
        RdResourceDir oneDir = rdResourceDirService.getOne(Wrappers.<RdResourceDir>lambdaQuery().eq(intResId != null, RdResourceDir::getId, intResId));
        // 如果是接口数据，则有自建系统
        if (oneDir.getResType() == 1) {
            rdResourceApplicationDetail.setApplyNumFather(randomNum)
                    .setApplyNumChild(applyNum)
                    .setResId(intResId)
                    .setResName(oneDir.getResName())
                    .setResType(oneDir.getResType())
                    .setResSituation(oneDir.getCollectionSituation())
                    .setType(oneDir.getResType())
                    .setState(3)
                    .setApplyDeptName(user.getOwnDeptName())
                    .setApplyUserId(userId)
                    .setApplyTime(date);
            // 获取前端传入的自建系统数据
            List<RdOrderApp> orderApps = rdResourceApplicationDetail.getOrderApps();
            Assert.isTrue(orderApps.isEmpty(), "您未选择自建系统!");
            // 批量新增自建系统
            boolean b = rdOrderAppService.addOrderApps(applyNum, orderApps, userId, date);
            Assert.isTrue(!b, "新增自建系统时失败!");
        } else if (oneDir.getResType() == 3) {
            // 如果是交换类，存入数据源和字段id
            rdResourceApplicationDetail.setApplyNumFather(randomNum)
                    .setApplyNumChild(applyNum)
                    .setResId(intResId)
                    .setResName(oneDir.getResName())
                    .setResType(oneDir.getResType())
                    .setResSituation(oneDir.getCollectionSituation())
                    .setType(oneDir.getResType())
                    .setState(3)
                    .setApplyDeptName(user.getOwnDeptName())
                    .setApplyUserId(userId)
                    .setApplyTime(date)
                    .setDbId(rdResourceApplicationDetail.getDbId())
                    .setItemId(rdResourceApplicationDetail.getItemId());
            // 存储数据源信息
            List<RdDbApp> dbApps = rdResourceApplicationDetail.getDbApps();
            Assert.isTrue(dbApps.isEmpty(), "您未选择资源信息!");
            Boolean aBoolean = rdDbAppService.addBetch(applyNum, dbApps);
            Assert.notTrue(aBoolean, "新增资源信息失败!");
        } else {
            // 如果是页面类，则没有自建系统和数据源数据
            rdResourceApplicationDetail.setApplyNumFather(randomNum)
                    .setApplyNumChild(applyNum)
                    // 此处idList为资源id
                    .setResId(intResId)
                    .setResName(oneDir.getResName())
                    .setResType(oneDir.getResType())
                    .setResSituation(oneDir.getCollectionSituation())
                    .setType(oneDir.getResType())
                    .setState(3)
                    .setApplyDeptName(user.getOwnDeptName())
                    .setApplyUserId(userId)
                    .setApplyTime(date);
        }
        rdResourceApplicationDetail.setDeptId(user.getOwnDeptId());
        boolean save = resAppDetailService.save(rdResourceApplicationDetail);
        Assert.notTrue(save, "新增本地订单时出错!");
        Integer id = rdResourceApplicationDetail.getId();
        // 提交申请到流程
        // 获取资源id
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("order_item_no", randomNum + "-" + intResId);
        // 准备资源id
        String resId = "[资源目录]-已归集" + intResId;
        map.put("res_id", resId);
        // 准备申请人id
        map.put("user_id", userId);
        list.add(map);
        Integer integer = approvalAllApi.lookResId(list);
        if (integer != 1) {
            boolean remove = resAppDetailService.removeById(id);
            Assert.notTrue(remove, "移除事务产生的订单出错!");
        }
        return true;
    }
}
